home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 7 / Amiga Format AFCD07 (Dec 1996, Issue 91).iso / serious / shareware / programming / ixemul-complete / ixemul / library / pipe.c < prev    next >
C/C++ Source or Header  |  1996-08-13  |  13KB  |  520 lines

  1. /*
  2.  *  This file is part of ixemul.library for the Amiga.
  3.  *  Copyright (C) 1991, 1992  Markus M. Wild
  4.  *  Portions Copyright (C) 1994 Rafael W. Luebbert
  5.  *
  6.  *  This library is free software; you can redistribute it and/or
  7.  *  modify it under the terms of the GNU Library General Public
  8.  *  License as published by the Free Software Foundation; either
  9.  *  version 2 of the License, or (at your option) any later version.
  10.  *
  11.  *  This library is distributed in the hope that it will be useful,
  12.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14.  *  Library General Public License for more details.
  15.  *
  16.  *  You should have received a copy of the GNU Library General Public
  17.  *  License along with this library; if not, write to the Free
  18.  *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19.  *
  20.  *  $Id: pipe.c,v 1.4 1994/06/19 15:14:19 rluebbert Exp $
  21.  *
  22.  *  $Log: pipe.c,v $
  23.  *  Revision 1.4  1994/06/19  15:14:19  rluebbert
  24.  *  *** empty log message ***
  25.  *
  26.  *  Revision 1.2  1992/07/04  19:21:08  mwild
  27.  *  (finally..) fix the bug which could cause pipe readers/writers to deadlock
  28.  *
  29.  * Revision 1.1  1992/05/14  19:55:40  mwild
  30.  * Initial revision
  31.  *
  32.  */
  33.  
  34. #define _KERNEL
  35. #include "ixemul.h"
  36. #include "kprintf.h"
  37.  
  38. #include <sys/ioctl.h>
  39. #include <string.h>
  40. #include "select.h"
  41.  
  42. /* information for the temporary implementation of pipes.
  43.    PIPE: has the big disadvantage that it blocks in the most unpleasent
  44.    situations, and doesn't send SIGPIPE to processes that write on
  45.    readerless pipes. Unacceptable for this library ;-)) */
  46.  
  47. #define PIPE_SIZE    5120
  48.  
  49. struct tmp_pipe {
  50.   u_short    tp_flags;        /* see below */
  51.   u_char    tp_buffer[PIPE_SIZE];
  52.   u_char    *tp_reader, *tp_writer;    /* buffer pointers.
  53.                        when tp_reader==tp_writer, no data
  54.                        is available */
  55.   struct Task   *tp_task;        /* task that waits for select */
  56. };
  57.  
  58. #define TPF_NO_READER    (1<<0)
  59. #define TPF_NO_WRITER    (1<<1)
  60. #define TPF_LOCKED    (1<<2)
  61. #define TPF_WANT_LOCK    (1<<3)
  62.  
  63. static int __pread(), __pwrite(), __pselect(), __pioctl(), __pclose();
  64. static struct tmp_pipe *__pinit();
  65.  
  66. static inline void
  67. __get_pipe (struct file *f)
  68. {
  69.   struct tmp_pipe *tp = f->f_tp;
  70.  
  71. retry:  
  72.   Forbid ();
  73.   for (;;)
  74.     {
  75.       if (!(tp->tp_flags & TPF_LOCKED))
  76.         {
  77.           tp->tp_flags &= ~TPF_WANT_LOCK;
  78.           tp->tp_flags |= TPF_LOCKED;
  79.           /* got it ! */
  80.           break;
  81.     }
  82.       tp->tp_flags |= TPF_WANT_LOCK;
  83.       KPRINTF_DISABLED (("__get_pipe: going to sleep\n"));
  84.       if (ix_sleep ((caddr_t)&tp->tp_flags, "get_pipe") < 0)
  85.         {
  86.       KPRINTF_DISABLED (("__get_pipe: interrupted\n"));
  87.       Permit ();
  88.       setrun (FindTask (0));
  89.           goto retry;
  90.         }
  91.       KPRINTF_DISABLED (("__get_pipe: back from sleep (not interrupted)\n"));
  92.       /* have to always recheck whether we really got the lock */
  93.     }
  94.   Permit ();      
  95. }
  96.  
  97. static inline void
  98. __release_pipe (struct file *f)
  99. {
  100.   struct tmp_pipe *tp = f->f_tp;
  101.  
  102.   Forbid ();
  103.   if (tp->tp_flags & TPF_WANT_LOCK)
  104.     ix_wakeup ((u_int)&tp->tp_flags);
  105.     
  106.   tp->tp_flags &= ~(TPF_WANT_LOCK|TPF_LOCKED);
  107.   Permit ();
  108. }
  109.  
  110.  
  111. int
  112. pipe (int pv[2])
  113. {
  114.   struct file *f1, *f2;
  115.   struct tmp_pipe *tp;
  116.   int res, err, omask;
  117.   
  118.   omask = syscall (SYS_sigsetmask, ~0);
  119.   res = -1; 
  120.   err = EMFILE;
  121.   if ((tp = __pinit ()))
  122.     {
  123.       if (! falloc (&f1, pv))
  124.         {
  125.           if (! falloc (&f2, pv+1))
  126.             {
  127.           f1->f_tp     = tp;
  128.           f1->f_stb.st_mode = 0666 | S_IFCHR;
  129.           f1->f_stb.st_size = PIPE_SIZE;
  130.           f1->f_stb.st_blksize = 512;
  131.           f1->f_flags  = FREAD;
  132.           f1->f_type   = DTYPE_PIPE;
  133.           f1->f_read   = __pread;
  134.           f1->f_write  = 0;
  135.           f1->f_ioctl  = __pioctl;
  136.           f1->f_close  = __pclose;
  137.           f1->f_select = __pselect;
  138.  
  139.           f2->f_tp     = tp;
  140.           f2->f_stb.st_mode = 0666 | S_IFCHR;
  141.           f2->f_stb.st_size = PIPE_SIZE;
  142.           f2->f_stb.st_blksize = 512;
  143.           f2->f_flags  = FWRITE;
  144.           f2->f_type   = DTYPE_PIPE;
  145.           f2->f_read   = 0;
  146.           f2->f_write  = __pwrite;
  147.           f2->f_ioctl  = __pioctl;
  148.           f2->f_close  = __pclose;
  149.           f2->f_select = __pselect;
  150.  
  151.           res = err =0;
  152.           goto ret;
  153.         }
  154.       f1->f_count = 0;
  155.     }
  156.  
  157.       kfree (tp);
  158.     }
  159.  
  160. ret:
  161.   syscall (SYS_sigsetmask, omask);
  162.  
  163.   errno = err;
  164.   KPRINTF_DISABLED (("&errno = %lx, errno = %ld\n", &errno, errno));
  165.   return res;
  166. }
  167.  
  168. static struct tmp_pipe *
  169. __pinit (void)
  170. {
  171.   struct tmp_pipe *tp = (struct tmp_pipe *) kmalloc (sizeof (*tp));
  172.   
  173.   if (tp)
  174.     {
  175.       tp->tp_flags = 0;
  176.       tp->tp_reader = tp->tp_writer = tp->tp_buffer;
  177.       tp->tp_task = 0;
  178.     }
  179.  
  180.   return tp;
  181. }
  182.  
  183. static int
  184. __pclose (struct file *f)
  185. {
  186.   ix_lock_base ();
  187.  
  188.   f->f_count--;
  189.  
  190.   if (f->f_count == 0)
  191.     {
  192.       if (f->f_read)
  193.         f->f_tp->tp_flags |= TPF_NO_READER;
  194.       else
  195.     f->f_tp->tp_flags |= TPF_NO_WRITER;
  196.     
  197.       if ((f->f_tp->tp_flags & (TPF_NO_READER|TPF_NO_WRITER)) ==
  198.       (TPF_NO_READER|TPF_NO_WRITER))
  199.     kfree (f->f_tp);
  200.       else
  201.     ix_wakeup ((u_int)f->f_tp);
  202.     }
  203.  
  204.   ix_unlock_base ();
  205.  
  206.   return 0;
  207. }
  208.  
  209. static int
  210. __pread (struct file *f, char *buf, int len)
  211. {
  212.   int omask = syscall (SYS_sigsetmask, ~0);
  213.   int err = errno;
  214.   int really_read = 0;
  215.   struct tmp_pipe *tp = f->f_tp;
  216.  
  217.   __get_pipe (f);
  218.  
  219.   while (len)
  220.     {
  221.       if (tp->tp_reader == tp->tp_writer)
  222.     {
  223.       KPRINTF_DISABLED (("__pread: len == %ld, buffer full\n", len));
  224.       if (tp->tp_flags & TPF_NO_WRITER)
  225.         {
  226.           KPRINTF_DISABLED (("__pread: EOF\n"));
  227.           err = 0;
  228.           break;
  229.         }
  230.     
  231.       if (f->f_flags & FNDELAY)
  232.         {
  233.           if (! really_read)
  234.         {
  235.           really_read = -1;
  236.           err = EAGAIN;
  237.         }
  238.           break;
  239.         }
  240.       else if (really_read)
  241.         {
  242.           err = 0;
  243.           break;
  244.         }
  245.       else
  246.         {
  247.           int sleep_rc;
  248.           KPRINTF_DISABLED (("__pread: going to sleep.\n"));
  249.           /* wait for something to be read or all readers to close */
  250.           Forbid ();
  251.           /* sigh.. Forbid() is necessary, or the other end may change
  252.              the pipe, and in the worst case also settle for sleep(), and
  253.              there it is.. deadlock.. */
  254.           __release_pipe (f);
  255.  
  256.           /* make write interruptible */
  257.           syscall (SYS_sigsetmask, omask);
  258.           sleep_rc = ix_sleep ((caddr_t)tp, "pwrite");
  259.           Permit ();
  260.           if (sleep_rc < 0)
  261.             setrun (FindTask (0));
  262.           omask = syscall (SYS_sigsetmask, ~0);
  263.  
  264.           __get_pipe (f);
  265.           continue;        /* retry */
  266.         }
  267.     }
  268.       else
  269.     {
  270.       /* okay, there's something to read from the pipe */
  271.       if (tp->tp_reader > tp->tp_writer)
  272.         {
  273.           /* read till end of buffer and wrap around */
  274.           int avail = PIPE_SIZE - (tp->tp_reader - tp->tp_buffer);
  275.           int do_read = len < avail ? len : avail;
  276.  
  277.           /* KPRINTF_DISABLED (("__pread-1: reading %ld bytes.\n", do_read)); */
  278.  
  279.           really_read += do_read;
  280.           bcopy (tp->tp_reader, buf, do_read);
  281.           len -= do_read;
  282.           buf += do_read;
  283.           tp->tp_reader += do_read;
  284.           if (tp->tp_reader - tp->tp_buffer == PIPE_SIZE)
  285.         /* wrap around */
  286.         tp->tp_reader = tp->tp_buffer;
  287.         }
  288.       if (len && tp->tp_reader < tp->tp_writer)
  289.         {
  290.           int avail = tp->tp_writer - tp->tp_reader;
  291.           int do_read = len < avail ? len : avail;
  292.  
  293.           /* KPRINTF_DISABLED (("__pread-2: reading %ld bytes.\n", do_read)); */
  294.  
  295.           really_read += do_read;
  296.           bcopy (tp->tp_reader, buf, do_read);
  297.           tp->tp_reader += do_read;
  298.           len -= do_read;
  299.           buf += do_read;
  300.         }
  301.     }
  302.  
  303.       ix_wakeup ((u_int)tp);
  304.     }
  305.  
  306.   __release_pipe (f);
  307.  
  308.   syscall (SYS_sigsetmask, omask);
  309.   errno = err;
  310.   KPRINTF_DISABLED (("&errno = %lx, errno = %ld\n", &errno, errno));
  311.   return really_read;
  312. }
  313.  
  314.  
  315. static int
  316. __pwrite (struct file *f, char *buf, int len)
  317. {
  318.   int  omask = syscall (SYS_sigsetmask, ~0);
  319.   int err = errno;
  320.   int really_written = 0;
  321.   struct tmp_pipe *tp = f->f_tp;
  322.  
  323.   __get_pipe (f);
  324.  
  325.   while (len)
  326.     {
  327.       if (tp->tp_flags & TPF_NO_READER)
  328.     {
  329.       KPRINTF_DISABLED (("__pwrite: SIGPIPE\n"));
  330.       really_written = -1;
  331.       err = EPIPE;
  332.       /* this is something no `real' Amiga pipe handler will do ;-)) */
  333.       _psignal (FindTask (0), SIGPIPE);
  334.       break;
  335.         }
  336.     
  337.       /* buffer full ?? */
  338.       if (tp->tp_reader == tp->tp_writer + 1
  339.       || (tp->tp_reader == tp->tp_buffer 
  340.           && tp->tp_writer == tp->tp_buffer + PIPE_SIZE - 1))
  341.     {
  342.       KPRINTF_DISABLED (("__pwrite: buffer full, len == %ld\n", len));
  343.       if (f->f_flags & FNDELAY)
  344.         {
  345.           if (! really_written)
  346.             {
  347.               really_written = -1;
  348.               err = EAGAIN;
  349.             }
  350.           break;
  351.         }
  352.       else
  353.         {
  354.           int sleep_rc;
  355.           KPRINTF_DISABLED (("__pwrite: going to sleep\n"));
  356.           /* wait for something to be read or all readers to close */
  357.           Forbid ();
  358.           /* sigh.. Forbid() is necessary, or the other end may change
  359.              the pipe, and in the worst case also settle for sleep(), and
  360.              there it is.. deadlock.. */
  361.           __release_pipe (f);
  362.  
  363.           /* make write interruptible */
  364.           syscall (SYS_sigsetmask, omask);
  365.           sleep_rc = ix_sleep ((caddr_t)tp, "pwrite");
  366.           Permit ();
  367.           if (sleep_rc < 0)
  368.             setrun (FindTask (0));
  369.           omask = syscall (SYS_sigsetmask, ~0);
  370.  
  371.           __get_pipe (f);
  372.           continue;        /* retry */
  373.         }
  374.     }
  375.       else
  376.     {
  377.       /* okay, there's some space left to write to the pipe */
  378.  
  379.       if (tp->tp_writer >= tp->tp_reader)
  380.         {
  381.           /* write till end of buffer */
  382.           int avail = PIPE_SIZE - 1 - (tp->tp_writer - tp->tp_buffer);
  383.           int do_write;
  384.  
  385.           if (tp->tp_reader > tp->tp_buffer)
  386.             avail++;
  387.           do_write = len < avail ? len : avail;
  388.  
  389.           /* KPRINTF_DISABLED (("__pwrite-1: writing %ld bytes.\n", do_write)); */
  390.           really_written += do_write;
  391.           bcopy (buf, tp->tp_writer, do_write);
  392.           len -= do_write;
  393.           buf += do_write;
  394.           tp->tp_writer += do_write;
  395.           if (tp->tp_writer - tp->tp_buffer == PIPE_SIZE)
  396.             tp->tp_writer = tp->tp_buffer;
  397.         }
  398.  
  399.       if (tp->tp_writer < tp->tp_reader - 1)
  400.         {
  401.           int avail = tp->tp_reader - tp->tp_writer - 1;
  402.           int do_write = len < avail ? len : avail;
  403.  
  404.           /* KPRINTF_DISABLED (("__pwrite-2: writing %ld bytes.\n", do_write)); */
  405.           really_written += do_write;
  406.           bcopy (buf, tp->tp_writer, do_write);
  407.           tp->tp_writer += do_write;
  408.           len -= do_write;
  409.           buf += do_write;
  410.         }
  411.       Forbid();
  412.       if (tp->tp_task)
  413.         Signal(tp->tp_task, 1UL << u.u_pipe_sig);
  414.       Permit();
  415.     }
  416.     
  417.       ix_wakeup ((u_int)tp);
  418.     }
  419.  
  420.   __release_pipe (f);
  421.  
  422.   syscall (SYS_sigsetmask, omask);
  423.   errno = err;
  424.   KPRINTF_DISABLED (("&errno = %lx, errno = %ld\n", &errno, errno));
  425.   return really_written;
  426. }
  427.  
  428. static int
  429. __pselect (struct file *f, int select_cmd, int io_mode,
  430.        fd_set *ignored, u_long *also_ignored)
  431. {
  432.   struct tmp_pipe *tp = f->f_tp;
  433.  
  434.   SetSignal(0, 1UL << u.u_pipe_sig);  /* reset signal */
  435.   tp->tp_task = NULL;
  436.   if (select_cmd == SELCMD_CHECK || select_cmd == SELCMD_POLL)
  437.     {
  438.       /* we support both, read and write checks (hey, something new ;-)) */
  439.       if (io_mode == SELMODE_IN)
  440.     return tp->tp_reader != tp->tp_writer;
  441.       else if (io_mode == SELMODE_OUT)
  442.     return !(tp->tp_reader == tp->tp_writer + 1
  443.          || (tp->tp_reader == tp->tp_buffer 
  444.              && tp->tp_writer == tp->tp_buffer + PIPE_SIZE - 1));
  445.     }
  446.  
  447.   tp->tp_task = FindTask(0);
  448.   return 1UL << u.u_pipe_sig;
  449. }
  450.  
  451. static int
  452. __pioctl (struct file *f, unsigned int cmd, unsigned int inout,
  453.           unsigned int arglen, unsigned int arg)
  454. {
  455.   int omask;
  456.   int result = 0;
  457.   struct tmp_pipe *tp = f->f_tp;
  458.   
  459.   omask = syscall (SYS_sigsetmask, ~0);
  460.   __get_pipe (f);
  461.  
  462.   switch (cmd)
  463.     {
  464.     case FIONREAD:
  465.       {
  466.     unsigned int *pt = (unsigned int *)arg;
  467.     if (tp->tp_reader < tp->tp_writer)
  468.       *pt = tp->tp_writer - tp->tp_reader;
  469.     else if (tp->tp_reader > tp->tp_writer)
  470.       *pt = PIPE_SIZE - (tp->tp_reader - tp->tp_writer);
  471.     else
  472.       *pt = 0;
  473.     result = 0;
  474.         break;
  475.       }
  476.  
  477.     case FIONBIO:
  478.       {
  479.     result = f->f_flags & FNDELAY ? 1 : 0;
  480.     if (*(unsigned int *)arg)
  481.       f->f_flags |= FNDELAY;
  482.     else
  483.       f->f_flags &= ~FNDELAY;
  484.     /* I didn't find it documented in a manpage, but I assume, we
  485.      * should return the former state, not just zero.. */
  486.     break;
  487.       }
  488.  
  489.     case FIOASYNC:
  490.       {
  491.     /* DOESN'T WORK YET */
  492.  
  493.     int flags = *(unsigned long*)arg;
  494.     result = f->f_flags & FASYNC ? 1 : 0;
  495.     if (flags)
  496.       f->f_flags |= FASYNC;
  497.     else
  498.       f->f_flags &= ~FASYNC;
  499.  
  500.     /* ATTENTION: have to call some function here in the future !!! */
  501.  
  502.     /* I didn't find it documented in a manpage, but I assume, we
  503.      * should return the former state, not just zero.. */
  504.     break;
  505.       }
  506.  
  507.     case FIOCLEX:
  508.     case FIONCLEX:
  509.     case FIOSETOWN:
  510.     case FIOGETOWN:
  511.       /* this is no error, but nevertheless we don't take any actions.. */      
  512.       result = 0;
  513.       break;
  514.     }
  515.  
  516.   __release_pipe (f);
  517.   syscall (SYS_sigsetmask, omask);
  518.   return result;
  519. }
  520.